package com.yanqu.road.server.manger.kowloon.battle.role.enemy;

import com.yanqu.road.entity.kowloon.battle.KowloonBattleEnemyData;
import com.yanqu.road.entity.kowloon.common.KowloonRange;
import com.yanqu.road.entity.kowloon.enums.battle.eKowloonBulletType;
import com.yanqu.road.entity.kowloon.enums.battle.eKowloonEnemyDirection;
import com.yanqu.road.entity.kowloon.enums.battle.eKowloonEnemyState;
import com.yanqu.road.logic.model.kowloon.KowloonConfig;
import com.yanqu.road.server.manger.kowloon.battle.KowloonGame;
import com.yanqu.road.server.manger.kowloon.battle.buff.KowloonBuff;
import com.yanqu.road.entity.kowloon.common.Rect;
import com.yanqu.road.entity.kowloon.common.Vec2;
import com.yanqu.road.server.manger.kowloon.battle.buff.KowloonBuffEffect;
import com.yanqu.road.server.manger.kowloon.battle.helper.KowloonEnemyDeadParam;
import com.yanqu.road.server.manger.kowloon.battle.role.KowloonRole;
import com.yanqu.road.server.manger.kowloon.battle.role.bullet.KowloonBullet;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.config.Config;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class KowloonEnemy extends KowloonRole {
    public final static double BEATBACK_SPEED = 1000;

    protected Logger logger = LogManager.getLogger(KowloonEnemy.class.getName());

    private KowloonBattleEnemyData data;

    /**
     * 路径
     */
    private LinkedList<Vec2> path = new LinkedList<>();

    private eKowloonEnemyState state = eKowloonEnemyState.Move;

    private Rect hurtRect;

    private long hp;

    private eKowloonEnemyDirection direction;

    private double speedReduce;

    private List<KowloonBuff> buffList = new ArrayList<>();

    /** 瞬间移动计数，一次瞬间移动teleportCount从0到30 */
    private int teleportCount = 0;

    private double[] buffCDTime = { 0, 0, 0 };

    public KowloonEnemy(KowloonGame game) {
        super(game);
    }

    public KowloonEnemy(KowloonGame game, KowloonBattleEnemyData enemyData) {
        super(game);
        this.initData(enemyData);
    }

    private void initData(KowloonBattleEnemyData enemyData) {
        this.data = enemyData;
        this.path = enemyData.getPath();
        Vec2 first = this.path.removeFirst();
        this.pos = new Vec2(first.getX(), first.getY());
        this.direction = eKowloonEnemyDirection.Down;
        KowloonRange hitRange = this.data.getAttributeData().getHitRange();
        this.hurtRect = new Rect(pos.getX() - hitRange.getWidth() / 2.0, pos.getY(), hitRange.getWidth(),
                hitRange.getHeight());
        this.hp = enemyData.getAttributeData().getHp();
        this.buffCDTime[0] = 0;
        this.buffCDTime[1] = 0;
        this.buffCDTime[2] = 0;
    }

    @Override
    public void updateData(double dt) {
        super.updateData(dt);
        switch (this.state) {
            case Move:
                this.updateBuff(dt);
                double speedReduce = 0;
                double beatBackY = 0;
                for (KowloonBuff buff : buffList) {
                    List<KowloonBuffEffect> effectList = buff.getBuffEffect();
                    for (KowloonBuffEffect effect : effectList) {
                        // 目前buff只有速度类的效果
                        switch (effect.getEffectType()) {
                            case Speed:
                                if (effect.getEffectArg() > speedReduce) {
                                    speedReduce = effect.getEffectArg();
                                }
                                break;
                            case BeatBack:
                                if (effect.getEffectArg() > beatBackY) {
                                    beatBackY = effect.getEffectArg();
                                }
                                break;
                        }
                    }
                }
                if (this.pos.getY() >= beatBackY) {
                    beatBackY = 0;
                }
                this.speedReduce = speedReduce;
                double speed = this.data.getAttributeData().getMoveSpeed() * (1000 - speedReduce) / 1000.0;
                if (this.path != null && !this.path.isEmpty()) {
                    Vec2 targetPos = this.path.get(0);
                    if (targetPos.getMoveType() == 1) {// 闪现
                        this.teleportCount++;
                        this.speed.setX(0);
                        this.speed.setY(0);
                        if (this.teleportCount == 15) {
                            this.pos.setX(targetPos.getX());
                            this.pos.setY(targetPos.getY());
                        } else if (this.teleportCount >= 30) {
                            this.path.removeFirst();
                        }
                    } else if (beatBackY > 0 && this.pos.getY() < 1200) {   // 击退
                        this.speed.setX(0);
                        double moveDistance = BEATBACK_SPEED * dt;
                        double targetDistance = beatBackY - this.pos.getY();
                        if (moveDistance > targetDistance) {
                            this.speed.setY(targetDistance / dt);
                        } else {
//                            double t = targetDistance * dt / moveDistance;
//                            this.speed.setY((targetPos.getY() - this.pos.getY()) / t);
                            this.speed.setY(BEATBACK_SPEED);
                        }
                    } else {// 普通移动
                        double moveDistance = speed * dt;
                        if (moveDistance == 0) {
                            this.speed.setX(0);
                            this.speed.setY(0);
                        } else {
                            double targetDistance = game.distance(this.pos, targetPos);
                            if (moveDistance > targetDistance) {
                                this.speed.setX((targetPos.getX() - this.pos.getX()) / dt);
                                this.speed.setY((targetPos.getY() - this.pos.getY()) / dt);
                                this.path.removeFirst();
                            } else {
                                double t = targetDistance * dt / moveDistance;
                                this.speed.setX((targetPos.getX() - this.pos.getX()) / t);
                                this.speed.setY((targetPos.getY() - this.pos.getY()) / t);
                            }
                        }
                        if (this.pos.getX() > targetPos.getX()) {
                            this.direction = eKowloonEnemyDirection.Right;
                        } else if (this.pos.getX() == targetPos.getX()) {
                            this.direction = eKowloonEnemyDirection.Down;
                        } else {
                            this.direction = eKowloonEnemyDirection.Left;
                        }
                    }
                }
                break;
        }
    }

    public void addBuffByBullet(KowloonBullet bullet) {
        int buffNum;
        if (bullet.getBulletType() == eKowloonBulletType.Spear) {
            buffNum = this.getBuffNumByType(bullet.bulletType, bullet.shooter.id);
        } else {
            buffNum = this.getBuffNumByType(bullet.bulletType, null);
        }
        int maxBuffNum = bullet.buffParam.getBuffMaxCount();
        if (buffNum < maxBuffNum) {
            int buffCDIndex = -1;
            switch (bullet.bulletType) {
                case Fish:
                    buffCDIndex = 0;
                    break;
                case Inkfish:
                case Amulet:
                    buffCDIndex = 1;
                    break;
                case Football:
                    buffCDIndex = 2;
                    break;

            }
            // 如果没有的话初始化一下
            while (this.data.getBuffCd().size() <= buffCDIndex) {
                this.data.getBuffCd().add(0);
            }
            if (buffCDIndex >= 0 && this.data.getBuffCd().get(buffCDIndex) > 0) {
                if (this.buffCDTime[buffCDIndex] < game.gameTime) {
                    this.buffCDTime[buffCDIndex] = game.gameTime + this.data.getBuffCd().get(buffCDIndex);
                } else {
                    return;
                }

            }
            KowloonBuff buff = KowloonBuff.createBuff(game, bullet, this);
            this.buffList.add(buff);
        }
    }

    public void updateBuff(double dt) {
        for (int i = 0; i < buffList.size(); i++) {
            KowloonBuff buff = buffList.get(i);
            buff.update(dt);
        }
    }

    public void removeBuff(KowloonBuff buff) {
        buffList.removeIf(t -> t.equals(buff));
    }

    public void clearBuff() {
        for (int i = 0; i < buffList.size(); i++) {
            KowloonBuff buff = buffList.get(i);
            buff.clear();
        }
        this.buffList = new ArrayList<>();
    }

    /**
     * 获取同一种类型的buff数
     */
    private int getBuffNumByType(eKowloonBulletType buffType, Integer casterId) {
        int num = 0;
        for (KowloonBuff buff : buffList) {
            if (buff.type == buffType && (casterId == null || buff.caster.id == casterId)) {
                num++;
            }
        }
        return num;
    }

    @Override
    public void updatePos(double dt) {
        if (this.state == eKowloonEnemyState.Move) {
            super.updatePos(dt);
            this.hurtRect.setX(this.pos.getX() - this.hurtRect.getWidth() / 2.0);
            this.hurtRect.setY(this.pos.getY());
        }
    }

    @Override
    public void updateAI(double dt) {
        switch (this.state) {
            case Move:
                if (this.path.size() == 0) {// 路走完了
                    this.pass();
                }
                break;
            case Dead:
                break;
            case Pass:
                break;
            default:
                break;
        }
    }

    public void stateChange(eKowloonEnemyState state) {
        this.state = state;
    }

    public boolean isAlive() {
        return this.hp > 0 && this.state == eKowloonEnemyState.Move;
    }

    public void beHurt(eKowloonBulletType bulletType, double damage) {
        this.hp -= damage;
        if (this.hp <= 0) {
            this.dead();
        }
        if (Config.isDebug()) {
            logger.info("敌人id:{},位置:x:{},y:{},受到伤害:{},当前血量:{},子弹类型：{}", this.id, this.pos.getX(), this.pos.getY(),
                    damage,
                    this.hp, bulletType);
        }
    }

    /**
     * 通过表现
     */
    public void pass() {
        this.stateChange(eKowloonEnemyState.Pass);
        // 摊位扣血,这里和客户端不一样，需要服务器计算
        game.beAttacked(this.getData().getUniqueId(), (int) this.data.getAttributeData().getAttack());
        this.hp = 0;
        this.recycle();
        this.stateChange(eKowloonEnemyState.Finish);
    }

    /**
     * 死亡表现
     */
    public void dead() {
        this.stateChange(eKowloonEnemyState.Dead);
        this.recycle();

        // 死亡爆炸
        if (!this.data.getDeadBornEnemyList().isEmpty()) {
            // 生成地痞
            for (KowloonBattleEnemyData enemyData : data.getDeadBornEnemyList()) {
                enemyData.setBornTime((int) game.getGameTime());
                Vec2 first = enemyData.getPath().getFirst();
                first.setX(this.pos.getX() + first.getX());
                first.setY(this.pos.getY() + first.getY());
                enemyData.getPath().addLast(new Vec2(first.getX(), KowloonConfig.BOOTH_PIXEL));

                // 需要传回给前端
                KowloonEnemyDeadParam deadParam = new KowloonEnemyDeadParam();
                deadParam.setBornTime(enemyData.getBornTime());
                deadParam.setPath(enemyData.getPath());
                game.getDeadParamMap().put(enemyData.getUniqueId(), deadParam.clone());

                // 添加敌人
                game.addEnemy(enemyData);
            }
        }

        this.stateChange(eKowloonEnemyState.Finish);
    }

    public void recycle() {

    }

    public KowloonBattleEnemyData getData() {
        return data;
    }

    public LinkedList<Vec2> getPath() {
        return path;
    }

    public eKowloonEnemyState getState() {
        return state;
    }

    public Rect getHurtRect() {
        return hurtRect;
    }

    public long getHp() {
        return hp;
    }

    public eKowloonEnemyDirection getDirection() {
        return direction;
    }

    public double getSpeedReduce() {
        return speedReduce;
    }

    public List<KowloonBuff> getBuffList() {
        return buffList;
    }
}
